/**
 * state 状态（可变）数据
 *
 * PS: 只能在 类组件使用 state。函数组件没有 state [16.8.0 新增 hook 之前]
 *    类组件      又称为 有状态组件
 *    函数组件    又称为 无状态组件
 *
 * state 的使用：
 *    1. 初始化 state 数据
 *    2. 使用 state 数据
 *    3. 更新 state 数据
 *
 * 初始化 state 数据:
 *    1. 在 构造函数 中， 给 this.state 赋值
 *    2. public class fields 语法
 *
 * 使用 state 数据:
 *    1. this.state.xxx
 *    2. 先解构出来再使用
 *
 * 更新 state 数据:
 *    1. state 数据是不能直接修改的，必须使用 setState 的函数来修改
 *    2. setState 异步还是同步的问题
 *        2.1 18版本前 setState 可能是异步的。
 *        2.2 18版本后通过createRoot()创建容器的方式的化，setState一定是异步的。
 *    3. setState 多次调用是会合并处理的
 *        3.1 如果 setState 传递的是对象的化，会把多个 setState 的对象合并到一起统一做一次修改
 *        3.2 如果 setState 传递的是函数的化，会把上一个函数的执行结果传递给下一个函数作为参数
 *
 *        this.setState(() => {
 *            return {
 *              age: 10
 *            }
 *        })
 *        this.setState(() => {
 *            return {
 *              age: 20
 *            }
 *        })
 *
 * setState 的语法：
 *    1. 对象语法
 *      this.setState({
 *
 *      })
 *    2. 函数语法
 *      this.setState((prevState) => {
 *          return newState
 *      })
 *    3. 第二个参数语法
 *      this.setState({}, () => {})
 *      this.setState(() => {}, () => {})
 *
 *      PS: 第二个参数是个回调函数，该回调函数会在数据更新完成且真实DOM更新完成之后触发。类似Vue中 nextTick
 *
 * 正确的使用setState
 *    1. 必须通过setState来修改state数据。
 *    2. setState可能是异步的
 *    3. 多次的setState是会合并成一次。
 */

import React from "react";

// import Hello from "./Hello";

interface Props {}

interface IState {
  name: string;
  age: number;
}

class App extends React.Component<Props, IState> {
  // constructor(props: Props) {
  //   super(props); // 必须要先调用父类的构造函数，否则this有问题

  //   this.state = {
  //     name: "张三",
  //     age: 18,
  //   };
  // }

  // public class fields 语法，该数据会在实例对象本身
  state = {
    name: "张三",
    age: 18,
  };

  // public class fields 语法，该数据会在实例对象本身
  fn1 = () => {
    console.log("fn1");
    // 修改 name, 页面不会更新。
    // this.state.name = "里斯";

    // this.setState()
    this.setState(
      {
        name: "里斯",
      },
      () => {
        console.log("setState 的 callback", this.state.name);
        console.log(document.getElementById("ppp")?.innerHTML); // '姓名：里斯'
      }
    );

    // setState 可能是异步的，无法在 setState 之后立刻获取到最新的 state 数据
    console.log("setState 后立刻", this.state.name); // 张三
    console.log(document.getElementById("ppp")?.innerHTML); // '姓名：张三'
  };

  // 常规的类中函数定义语法，该函数将会在实例的原型上
  fn2() {}

  fn3 = () => {
    console.log("fn3");
    this.setState({
      age: this.state.age + 1,
    });
    this.setState({
      age: this.state.age + 1,
    });
    this.setState({
      age: this.state.age + 1,
    });
    this.setState({
      age: this.state.age + 1,
    });

    // this.setState((prevState) => {
    //   // {..., age: 18}
    //   return {
    //     age: prevState.age + 1,
    //   };
    // });
    // this.setState((prevState) => {
    //   // {..., age: 19}
    //   return {
    //     age: prevState.age + 1,
    //   };
    // });
    // this.setState((prevState) => {
    //   // {..., age: 19}
    //   return {
    //     age: prevState.age + 1,
    //   };
    // });
    // this.setState((prevState) => {
    //   // {..., age: 19}
    //   return {
    //     age: prevState.age + 1,
    //   };
    // });

    // 执行该回调函数，得到一个对象 { age: 10 }, 将这个对象与现有的 state数据合并得到一个 { name: '张三', age: 10 },再将这个对象传递给下一个setState的回调函数作为参数
    // this.setState((prevState) => {
    //   console.log("1", prevState); // {name: '张三', age: 18}
    //   return {
    //     age: 10,
    //   };
    // });
    // this.setState((prevState) => {
    //   console.log("2", prevState); // {name: '张三‘, age: 10}
    //   return {
    //     age: 20,
    //   };
    // });
  };

  render(): React.ReactNode {
    console.log("render", this);

    const { name, age } = this.state;

    return (
      <div>
        <h1>State</h1>
        <hr />
        <p id="ppp">姓名：{this.state.name}</p>
        <p>年龄：{age}</p>
        <button onClick={this.fn1}>修改姓名</button>
        <button onClick={this.fn3}>修改年龄</button>
      </div>
    );
  }
}

export default App;
